const PENDDING = 'pendding'
const FULLFILLED = 'fullfilled'
const REJECTED = 'rejected'


class MyPromise {
  constructor(exec) {
    this.status = PENDDING
    this.value = undefined
    this.reason = undefined
    this.onFullfilledFns = []
    this.onRejectedFns = []

    let resolve = (_value) => {
      if (this.status === PENDDING) {
        this.status = FULLFILLED
        this.value = _value
        while (this.onFullfilledFns.length > 0) {
          this.onFullfilledFns.shift()(_value)
        }
      }
    }

    let reject = (_reason) => {
      if (this.status === PENDDING) {
        this.status = REJECTED
        this.reason = _reason
        while (this.onRejectedFns.length > 0) {
          this.onRejectedFns.shift()(_reason)
        }
      }
    }

    try {
      exec(resolve, rejected)
    } catch (err) {
      reject(err)
    }
  }

  then(onFullfilled, onRejected) {
    let successCb = typeof onFullfilled === 'function' ? onFullfilled : v => v
    let failCb = typeof onRejected === 'function' ? onRejected : err => { throw err }

    return new MyPromise((resolve, reject) => {
      this.onFullfilledFns.push(() => {
        try {
          let x = successCb(this.value)
          x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
        } catch (err) {
          reject(err)
        }
      })
      this.onRejectedFns.push(() => {
        try {
          let x = failCb(this.reason)
          x instanceof MyPromise ? x.then(resolve, reject) : reject(x)
        } catch (err) {
          reject(err)
        }

      })
    })
  }
  // 就是只有onRejected回调的then
  catch(cb) {
    return this.then(null, cb)
  }
  // 直接创建一个新的Promise，内部直接调用resolve
  // 如果value是实例则直接返回
  static resolve(_value) {
    if (_value instanceof MyPromise) return _value
    return new MyPromise((resolve) => {
      resolve(_value)
    })
  }
  // 直接创建一个新的Promise，内部直接调用reject
  static reject(_reason) {
    return new MyPromise((resolve, reject) => {
      reject(_reason)
    })
  }
  // 无论如何都要执行：放到then中，
  // 后面可以接then，直接resolve
  finally(cb) {
    return this.then(value => {
      MyPromise.resolve(cb()).then(() => value)
    }, reason => {
      MyPromise.resolve(cb()).then(() => { throw reason })
    })
  }
  // 支持链式调用
  // 一个出了结果就直接resolve
  race(promiseArr) {
    return new MyPromise((resolve, reject) => {
      for (let promise of promiseArr) {
        MyPromise.resolve(promise).then(value => {
          resolve(value)
        }, reason => {
          reject(reason)
        })
      }
    })
  }

  all(promiseArr) {
    let results = []
    let count = 0
    return new MyPromise((resolve, reject) => {
      for (let promise of promiseArr) {
        MyPromise.resolve(promise).then(value => {
          results.push(value)
          count++
          if (count === promiseArr.length) {
            resolve(results)
          }
        }, reason => {
          reject(reason)
        })
      }
    })
  }
}


